/**
 * 贝塞尔曲线插值点
 *
 * 当前代码，存在非常多值得优化的代码
 */
function BezierLine() {

    /**
     * 生成贝塞尔曲线插值点
     *
     * @param {Array} points - 控制点数组，格式 [[x0, y0], [x1, y1], ...]
     * @param {Array} [res=[]] - 存储结果的数组（可选）
     * @param {number} [step=0.2] - 步长，取值越小曲线越精细
     * @returns {Array} 贝塞尔曲线上的点坐标数组
     */
    function createBezierCurvePoints(points, res, step = 0.2) {
        // 贝塞尔曲线阶数
        let n = points.length - 1;

        // 阶乘查找表
        const factorials = [1]; // 0! = 1
        for (let i = 1; i <= n; i++) {
            factorials[i] = factorials[i - 1] * i;
        }

        for (let t = 0; t <= 1; t = t + step) {
            res.push(multiplyBezier(points, b, factorials, t));
        }
    }


    /**
     * 高阶贝塞尔曲线
     *
     * @param points {Array} - 控制点数组，格式 [[x0, y0], [x1, y1], ...]
     * @param n {number} - 阶
     * @param factorials {Array} - 阶乘查找表
     * @param t {number} - 步长
     * @returns [x,y] ret
     */
    function multiplyBezier(points, n, factorials, t) {
        let Ptx = 0, Pty = 0;
        for (let i = 0; i <= n; i++) {
            const comb = factorials[n] / (factorials[i] * factorials[n - i]);
            Ptx += comb * Math.pow((1 - t), n - i) * Math.pow(t, i) * points[i][0];
            Pty += comb * Math.pow((1 - t), n - i) * Math.pow(t, i) * points[i][1];
        }
        return [Ptx, Pty];
    }

    /**
     * 2 阶贝塞尔曲线
     *
     * @param p0
     * @param p1
     * @param p2
     * @param t
     * @returns [x,y] ret
     */
    function quadraticBezier(p0, p1, p2, t) {
        // 使用数学公式计算贝塞尔曲线上的点
        const temp = 1 - t;
        const x = Math.pow(temp, 2) * p0[0] + 2 * temp * t * p1[0] + Math.pow(t, 2) * p2[1];
        const y = Math.pow(temp, 2) * p0[1] + 2 * temp * t * p1[1] + Math.pow(t, 2) * p2[1];
        return [x, y];
    }

    /**
     * 3 阶贝塞尔曲线
     *
     * @param p0
     * @param p1
     * @param p2
     * @param p3
     * @param t
     * @returns [x,y] ret
     */
    function cubicBezier(p0, p1, p2, p3, t) {
        const temp = 1 - t;
        const x = p0[0] * temp * temp * temp + 3 * p1[0] * t * temp * temp + 3 * p2[0] * t * t * temp + p3[0] * t * t * t;
        const y = p0[1] * temp * temp * temp + 3 * p1[1] * t * temp * temp + 3 * p2[1] * t * t * temp + p3[1] * t * t * t;
        return [x, y];
    }


    /**
     * p1 到 p2 进行 n 等分，取第 m 个点
     *
     * @param n
     * @param m
     * @param p1
     * @param p2
     */
    function dividedPoint(n, m, p1, p2) {
        return [(p2[0] - p1[0]) / n * m + p1[0], (p2[1] - p1[1]) / n * m + p1[1]]
    }

    /**
     * 平滑转角
     *
     * 使用高阶贝塞尔曲线算法，以正方形为例，得到的结果会是一个圆。
     *
     * 有些业务场景，只是希望角能变得圆润一些，这时候，使用 2 阶算法即可
     *
     * 比如：
     * 原始数据：(0,0),(5,0),(5,5)
     * 计算结果：(4,0),(5,0),(5,1)
     *
     * 需要从 (4,0) 开始绘制曲线，结束于 (5,1) 点
     *
     * @param p1
     * @param p2
     * @param p3
     * @param res
     */
    function smoothCorner(p1, p2, p3, res) {
        const denominator = 10;

        //计算 4/5 等分点
        const point1 = dividedPoint(denominator, denominator - 1, p1, p2);
        const point2 = p2;
        //计算 1/5 等分点
        const point3 = dividedPoint(denominator, 1, p2, p3);

        //开始点
        res.push(point1);
        //计算曲线坐标点
        quadraticBezier(point1, point2, point3, res);
        //结束点
        res.push(point3);
    }

    return {
        /**
         * 使所有的转角变平滑
         *
         * @param line 线段数组
         * @returns {*|*[]}
         */
        getPolygonLine: function (line) {
            if (line.length < 3) {
                console.error('图形点的数量不允许小于3：' + line);
                return line;
            } else {
                const n = line.length - 2, res = [];
                for (var i = 0; i < n; i++) {
                    smoothCorner(line[i], line[i + 1], line[i + 2], res);
                }
                //倒数第一个点
                smoothCorner(line[n], line[0], line[1], res);
                return res;
            }
        }
    }
}